package server.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import server.Server;

import messages.ServerParameters;
import messages.ServerServerMessage;

public class OutThread extends Thread {
	private boolean KeepGoing = true;
	private Socket outServerSocket;
	private ObjectInputStream outSInput;
	private ObjectOutputStream outSOutput;
	private ArrayList<ServerParameters> myServerList;
	private ServerOutIF server;
	private String outServerAddress;
	private int outServerPort;

	public OutThread(String outServerAddress, int outServerPort, ServerOutIF server,
			boolean reconnect) {
		this.server = server;
		this.outServerAddress = outServerAddress;
		this.outServerPort = outServerPort;
		myServerList = server.getMyServerList();

		// server.display(getDate() + "Trying connect to" + outServerAddress +
		// "/" + outServerPort);
		try { // create socket
			outServerSocket = new Socket(outServerAddress, outServerPort);
		} catch (Exception ec) {
			server.display(getDate() + "Error connectiong to: " + outServerAddress + "/"
					+ outServerPort + "\n" + ec);
//			System.exit(0);
		}

		try {// create output sream
			outSOutput = new ObjectOutputStream(outServerSocket.getOutputStream());
		} catch (IOException eIO) {
			server.display(getDate() + "Exception creating new output Streams: " + eIO);
			disconnect();
		}
		try {// send login information
			outSOutput.writeObject(new String(Server.SERVER));
			ServerParameters parameters = server.getMyServerParameters();
			outSOutput.writeObject(parameters);
		} catch (IOException eIO) {
			server.display(getDate() + "Exception doing login : " + eIO);
			// e.printStackTrace();
		}
		try {// create input stream
			outSInput = new ObjectInputStream(outServerSocket.getInputStream());
		} catch (IOException eIO) {
			server.display(getDate() + "Exception creating new Input Streams: " + eIO);
			disconnect();
		}
		try {// Receive server routing list
			myServerList = (ArrayList<ServerParameters>) outSInput.readObject();
		} catch (IOException eIO) {
			server.display(getDate() + "Exception doing login : " + eIO);
		} catch (ClassNotFoundException e) {
			server.display(getDate() + "Exception doing login : " + e);
		}

		ServerServerMessage ssm;
		if (!reconnect) {
			// System.out.println(" ## Servers table ## ");
			// if (myServerList != null) {
			// for (ServerParameters parameters : myServerList) {
			// System.out.println(" ### " + parameters.getAddress() + " ### "
			// + parameters.getPort());
			// }
			// }
			server.setMyServerList(myServerList);
			ssm = new ServerServerMessage(myServerList, server.getMyServerParameters());
		} else {
			myServerList = server.getMyServerList();

			// System.out.println(" ## Servers table ## reconnect");
			// if (myServerList != null) {
			// for (ServerParameters parameters : myServerList) {
			// System.out.println(" ### " + parameters.getAddress() + " ### "
			// + parameters.getPort());
			// }
			// }

			ssm = new ServerServerMessage(myServerList, server.getMyServerParameters());
		}

		try {
			// ssm.incrementCounter();
			outSOutput.writeObject(ssm);
		} catch (IOException e) {
			System.out.println(getDate() + "Errore trasmisione ssM");
			e.printStackTrace();
		}
		String msg = getDate() + "Connected with " + outServerSocket.getInetAddress()
				+ "/" + outServerSocket.getPort();
		server.display(msg);
	}

	@Override
	public void run() {
		while (KeepGoing) {
			ServerServerMessage msg = null;
			try {
				msg = (ServerServerMessage) outSInput.readObject();
				server.display(getDate() + msg.getMessageType());
			} catch (ClassNotFoundException | IOException e) {
				try {
					server.display(getDate() + "Exception receive data:" + e.toString()
							+ " disconnected from: " + outServerAddress + "/"
							+ outServerPort);
					server.disconnectOutServer();
					break;
				} catch (Exception e2) {
					break;
				}
			}
		}
	}

	public synchronized boolean writeMsg(ServerServerMessage msg) {
		msg.incrementCounter();
		if (msg.getCounter() >= server.getMyServerList().size()) {
			String tmpmsg = " ";
			if (msg.getMessageType() == ServerServerMessage.SERVERLIST) {
				for (ServerParameters parameters : msg.getServerList()) {
					tmpmsg = tmpmsg + " " + parameters.getAddress() + ":"
							+ parameters.getPort() + "::"
							+ parameters.getNumberOfClients();
				}
			}
			server.display(getDate() + "Remove old msg "
					+ msg.getParameters().getAddress() + "/"
					+ msg.getParameters().getPort() + ":" + msg.getCounter() + tmpmsg);
			return false;
		} else {
			if (!outServerSocket.isConnected()) {
				disconnect();
				return false;
			}
			try {
				outSOutput.writeObject(msg);
			}
			// if an error occurs, do not abort just inform the user
			catch (IOException e) {
				server.display(getDate() + "Exception send data:" + e.toString()
						+ " disconnected from: " + outServerAddress + "/" + outServerPort);
				disconnect();
				server.disconnectOutServer();
			}
			return true;
		}
	}

	public void disconnect() {
		this.server = null;
		try {
			if (outSInput != null) {
				outSInput.close();
			}
		} catch (IOException e) {
		}
		try {
			if (outSOutput != null) {
				outSOutput.close();
			}
		} catch (IOException e) {
		}
		try {
			if (outServerSocket != null) {
				outServerSocket.close();
			}

		} catch (IOException e) {
		}
	}

	private String getDate() {
		return "OutThread ";
	}
}
